<?php
// Copyright 2019 Hackware SpA <human@hackware.cl>
// "Hackware Web Services Core" is released under the MIT License terms.

namespace Hawese\Core;

use Illuminate\Support\Str;
use Exception;

/**
 * Token class.
 *
 * Currently supports 2 token types:
 * - HUMAN tokens can be used only once, but last a long time. Are used as an
 * alternative authentication mechanism instead of passwords. Currently used
 * for logins with "remember me" set and for users without a password (sent
 * via email).
 * - SYSTEM tokens are used to authenticate a computer that interacts with
 * the API.
 *
 * This should eventually be implemented using a more lightweight database.
 */
class Token extends TableModel
{
    public const HUMAN = 'human';
    public const SYSTEM = 'system';
    
    public static $table = 'tokens';
    public static $attributes = [
        'key' => ['required', 'string', 'min:10', 'max:255'],
        'secret' => ['required', 'string', 'min:10', 'max:255'],
        'type' => ['required', 'in:human,system'],
        'user_uid' => [
            'required', 'string', 'min:3', 'max:100'
        ],
        'created_at' => ['nullable', 'date'],
    ];

    public static $primary_key = 'key';
    protected static $incrementing = false;

    public static $foreign_keys = [
        'user_uid' => User::class,
    ];

    public function __toString()
    {
        return $this->key;
    }

    /**
     * Inserts a new token in database
     */
    public static function generate(string $type, string $user_uid): self
    {
        $secret = Str::random(64);
        $token = new Token([
            'key' => bin2hex(random_bytes(7)),
            'secret' => password_hash($secret, PASSWORD_DEFAULT),
            'type' => $type,
            'user_uid' => $user_uid
        ]);
        $token->insert();

        $token->secret = $secret; // return the secret in clear text just once
        return $token;
    }
}
